import com.alibaba.fastjson.JSON;
import lombok.extern.java.Log;
import org.apache.commons.lang3.StringUtils;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.contract.ContractInterface;
import org.hyperledger.fabric.contract.annotation.Contract;
import org.hyperledger.fabric.contract.annotation.Default;
import org.hyperledger.fabric.contract.annotation.Transaction;
import org.hyperledger.fabric.shim.ChaincodeException;
import org.hyperledger.fabric.shim.ChaincodeStub;

@Contract(name = "NFTContract")
@Default
@Log
public class NFTContract implements ContractInterface {


    //查询NFT
    @Transaction
    public NFTInfo queryNFT(final Context ctx, final String id) {
        ChaincodeStub stub = ctx.getStub();
        String NFTState = stub.getStringState(id);
        if (StringUtils.isBlank(NFTState)) {
            String errorMessage = String.format("编号%s的NFT不存在！", id);
            throw new ChaincodeException(errorMessage);
        }
        return JSON.parseObject(NFTState, NFTInfo.class);
    }


    //创建NFT
    @Transaction
    public NFTInfo createNFT(final Context ctx, final NFTInfo nftInfo) {
        ChaincodeStub stub = ctx.getStub();
        String NFTState = stub.getStringState(nftInfo.getId());
        if (StringUtils.isNotBlank(NFTState)) {
            String errorMessage = String.format("编号%s的NFT已经存在！", nftInfo.getId());
            throw new ChaincodeException(errorMessage);
        }
        String json = JSON.toJSONString(nftInfo);
        stub.putStringState(nftInfo.getId(), json);
        stub.setEvent("createNFTEvent", org.apache.commons.codec.binary.StringUtils.getBytesUtf8(json));
        return nftInfo;
    }


    //更新NFT
    @Transaction
    public NFTInfo updateNFT(final Context ctx, final NFTInfo nftInfo) {
        ChaincodeStub stub = ctx.getStub();
        String NFTState = stub.getStringState(nftInfo.getId());

        if (StringUtils.isBlank(NFTState)) {
            String errorMessage = String.format("编号%s的NFT不存在！", nftInfo.getId());
            throw new ChaincodeException(errorMessage);
        }

        String json = JSON.toJSONString(nftInfo);
        stub.putStringState(nftInfo.getId(), json);

        return nftInfo;
    }


    //删除NFT
    @Transaction
    public NFTInfo deleteNFT(final Context ctx, final String id) {
        ChaincodeStub stub = ctx.getStub();
        String NFTState = stub.getStringState(id);

        if (StringUtils.isBlank(NFTState)) {
            String errorMessage = String.format("编号%s的NFT不存在！", id);
            throw new ChaincodeException(errorMessage);
        }
        stub.delState(id);
        return JSON.parseObject(NFTState, NFTInfo.class);
    }


    //检测NFT是否存在
    @Transaction
    public boolean CheckNFTState(final Context ctx, final String id) {
        ChaincodeStub stub = ctx.getStub();
        String NFTState = stub.getStringState(id);
        return !StringUtils.isBlank(NFTState);
    }


    //NFT上架操作
    @Transaction
    public boolean PutawayNFT(final Context ctx, final String id) {
        ChaincodeStub stub = ctx.getStub();
        String NFTState = stub.getStringState(id);

        if (StringUtils.isBlank(NFTState)) {
            String errorMessage = String.format("编号%s的NFT不存在！", id);
            throw new ChaincodeException(errorMessage);
        }

        NFTInfo nftInfo = JSON.parseObject(NFTState, NFTInfo.class);

        if (nftInfo.getState().equals("1")) {
            String errorMessage = String.format("编号%s的NFT已经上架！", id);
            throw new ChaincodeException(errorMessage);
        }

        nftInfo.setState("1");
        String json = JSON.toJSONString(nftInfo);
        stub.putStringState(id, json);
        return true;
    }

    //修改NFT价格
    @Transaction
    public boolean ChangePrice(final Context ctx, final String id, final String newPrice){
        ChaincodeStub stub = ctx.getStub();
        String NFTState = stub.getStringState(id);

        if (StringUtils.isBlank(NFTState)) {
            String errorMessage = String.format("编号%s的NFT不存在！", id);
            throw new ChaincodeException(errorMessage);
        }

        NFTInfo nftInfo = JSON.parseObject(NFTState, NFTInfo.class);

        if (nftInfo.getState().equals("0")) {
            String errorMessage = String.format("编号%s的NFT未上架！", id);
            throw new ChaincodeException(errorMessage);
        }

        nftInfo.setPrice(newPrice);
        stub.putStringState(id,JSON.toJSONString(nftInfo));
        return true;
    }


    //交易（成功返回交易Hash）
    @Transaction
    public String transactionNFT(Context ctx, String nftId,String buyerId,String sellerId){
        ChaincodeStub stub = ctx.getStub();
        String buyerState = stub.getStringState(buyerId);
        String sellerState = stub.getStringState(sellerId);

        if (StringUtils.isBlank(buyerState)) {
            String errorMessage = "买方信息不存在！";
            throw new ChaincodeException(errorMessage);
        }

        if (StringUtils.isBlank(sellerState)) {
            String errorMessage = "卖方信息不存在！";
            throw new ChaincodeException(errorMessage);
        }

        UserInfo buyer = JSON.parseObject(buyerState, UserInfo.class);
        UserInfo seller = JSON.parseObject(sellerState, UserInfo.class);

        String nftState = stub.getStringState(nftId);

        if (StringUtils.isBlank(nftState)) {
            String errorMessage = String.format("编号%s的NFT不存在！", nftId);
            throw new ChaincodeException(errorMessage);
        }

        NFTInfo nftInfo = JSON.parseObject(nftState, NFTInfo.class);

        if (nftInfo.state.equals("0")) {
            String errorMessage = String.format("编号%s的NFT未上架！", nftId);
            throw new ChaincodeException(errorMessage);
        }

        double price = Double.parseDouble(nftInfo.getPrice());
        double buyerProperty = Double.parseDouble(buyer.getProperty());

        if(buyerProperty<price){
            String errorMessage = "买方资金不足，无法购买！";
            throw new ChaincodeException(errorMessage);
        }

        seller.setProperty(String.valueOf((Double.parseDouble(seller.getProperty())+price)));
        buyer.setProperty(String.valueOf(buyerProperty-price));
        nftInfo.setOwner(buyerId);
        nftInfo.setState("0");

        stub.putStringState(nftId,JSON.toJSONString(nftInfo));
        stub.putStringState(buyerId,JSON.toJSONString(buyer));
        stub.putStringState(sellerId,JSON.toJSONString(seller));

        return stub.getTxId();
    }


    //注册用户
    @Transaction
    public UserInfo regUser(Context ctx, UserInfo userInfo){
        ChaincodeStub stub = ctx.getStub();
        String userState = stub.getStringState(userInfo.getId());

        if (StringUtils.isNotBlank(userState)) {
            String errorMessage = String.format("编号%s的用户已经存在！", userInfo.getId());
            throw new ChaincodeException(errorMessage);
        }

        stub.putStringState(userInfo.getId(), JSON.toJSONString(userInfo));
        return userInfo;
    }

    //查询用户
    @Transaction
    public UserInfo findUser(Context ctx, String id){
        ChaincodeStub stub = ctx.getStub();
        String userState = stub.getStringState(id);

        if (StringUtils.isBlank(userState)) {
            String errorMessage = String.format("编号%s的用户不存在！", id);
            throw new ChaincodeException(errorMessage);
        }

        return JSON.parseObject(userState,UserInfo.class);
    }


    //增加用户资产
    @Transaction
    public boolean addUserProperty(final Context ctx,String userId,String value){
        ChaincodeStub stub = ctx.getStub();
        String userState = stub.getStringState(userId);

        if (StringUtils.isBlank(userState)) {
            String errorMessage = String.format("编号%s的用户不存在！", userId);
            throw new ChaincodeException(errorMessage);
        }

        UserInfo userInfo = JSON.parseObject(userState, UserInfo.class);
        userInfo.setProperty(String.valueOf(Double.parseDouble(userInfo.getProperty())+Double.parseDouble(value)));
        stub.putStringState(userId,JSON.toJSONString(userInfo));

        return true;
    }

    //用户修改密码
    @Transaction
    public boolean changeUserPwd(final Context ctx,String userId,String newPwd){
        ChaincodeStub stub = ctx.getStub();
        String userState = stub.getStringState(userId);

        if (StringUtils.isBlank(userState)) {
            String errorMessage = String.format("编号%s的用户不存在！", userId);
            throw new ChaincodeException(errorMessage);
        }

        UserInfo userInfo = JSON.parseObject(userState, UserInfo.class);
        userInfo.setPassword(newPwd);

        stub.putStringState(userId,JSON.toJSONString(userInfo));
        return true;
    }
}
